package com.cdxy.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeCloseRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cdxy.dmr.dataObject.*;
import com.cdxy.dmr.repository.*;
import com.cdxy.enums.BizErrorEnum;
import com.cdxy.enums.OrderEnum;
import com.cdxy.enums.PayChannelEnum;
import com.cdxy.model.dto.base.exception.BusinessException;
import com.cdxy.model.dto.base.exception.enums.CommonErrorEnum;
import com.cdxy.model.dto.base.resp.BasePageResp;
import com.cdxy.model.dto.req.*;
import com.cdxy.model.dto.resp.CreateOrderResp;
import com.cdxy.model.dto.resp.OrderDetailResp;
import com.cdxy.model.dto.resp.OrderListResp;
import com.cdxy.model.dto.resp.SuccessStatusAckResp;
import com.cdxy.model.info.OrderInfo;
import com.cdxy.model.info.OrderStatusInfo;
import com.cdxy.service.IRechargeService;
import com.cdxy.util.BeanUtil;
import com.cdxy.util.BizNoUtil;
import com.cdxy.util.MoneyUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author: tangy
 * @Date: 2020/4/7 17:13
 */
@Service
@Slf4j
public class RechargeServiceImpl implements IRechargeService {

    @Value("${alipay.gateWay}")
    private String gateWay;

    @Value("${alipay.privateKey}")
    private String privateKey;

    @Value("${alipay.publicKey}")
    private String publicKey;

    @Value("${alipay.aliPlublicKey}")
    private String aliPlublicKey;

    @Value("${alipay.appId}")
    private String appId;

    @Value("${alipay.sceneNotify}")
    private String sceneNotify;

    @Value("${alipay.hotelNotify}")
    private String hotelNotify;

    @Autowired
    private SceneRepository sceneRepository;

    @Autowired
    private SceneTicketRepository sceneTicketRepository;

    @Autowired
    private HotelRepository hotelRepository;

    @Autowired
    private HotelRoomRepository hotelRoomRepository;

    @Autowired
    private PayOrderRepository payOrderRepository;

    @Override
    public String aliPayNotifyScene(Map<String, String> param) {
        return aliPayNotify(param, OrderEnum.PayType.SCENE_ORDER_TICK);
    }

    @Override
    public String aliPayNotifyHotel(Map<String, String> params) {
        return aliPayNotify(params, OrderEnum.PayType.HOTEL_ORDER_ROOM);
    }

    @Override
    public void cancelOrder(CancelOrderReq cancelOrderReq) {
        Integer axUid = cancelOrderReq.getAxUid();
        PayOrderDO payOrderDO = payOrderRepository.getById(cancelOrderReq.getOrderId());
        if (payOrderDO == null) {
            throw new BusinessException(BizErrorEnum.ORDER_NOT_EXIST);
        }
        if (!axUid.equals(payOrderDO.getAxUid())) {
            log.error("用户取消订单。用户id不服。axUid:{},axUidReq:{}", axUid, payOrderDO.getAxUid());
            throw new BusinessException(BizErrorEnum.ORDER_PARAM_ERROR, "用户操作异常");
        }
        OrderEnum.OrderStatus orderStatus = OrderEnum.OrderStatus.valueOf(payOrderDO.getStatus());
        if (!(OrderEnum.OrderStatus.SUCCESS.name().equals(orderStatus.name()) || OrderEnum.OrderStatus.PAYING.name().equals(orderStatus.name()))) {
            log.error("取消订单操作异常.axUid:{},orderId{}", axUid, cancelOrderReq.getOrderId());
            throw new BusinessException(BizErrorEnum.CANCEL_OPTION_ERROR);
        }

        if (OrderEnum.OrderStatus.SUCCESS.name().equals(orderStatus.name())) {
            refundOrder(payOrderDO.getBizNo(), payOrderDO.getTotalAmount());
            payOrderRepository.updateStatusByOrderNoAndOldStatus(OrderEnum.OrderStatus.REFUND, payOrderDO.getBizNo(), orderStatus);
        } else if (OrderEnum.OrderStatus.PAYING.name().equals(orderStatus.name())) {
            payOrderRepository.updateStatusByOrderNoAndOldStatus(OrderEnum.OrderStatus.CANCEL, payOrderDO.getBizNo(), orderStatus);
        }
    }

    private String aliPayNotify(Map<String, String> params, OrderEnum.PayType payType) {
        // 商户业务流水号
        String outTradeNo = params.get("out_trade_no");
        // 支付宝交易号
        String tradeNo = params.get("trade_no");
        // 买家支付宝账号
        String buyerLogonId = params.get("buyer_logon_id");
        // 交易付款时间
        String gmtPayment = params.get("gmt_payment");
        // 交易状态
        String tradeStatus = params.get("trade_status");
        // 订单总金额
        Integer totalAmount = MoneyUtil.convertYuanToFen(params.get("total_amount"));

        // 交易成功的通知才处理
        if (!("TRADE_FINISHED".equalsIgnoreCase(tradeStatus) || "TRADE_SUCCESS".equalsIgnoreCase(tradeStatus))) {
            return "SUCCESS";
        }

        // 验签
        SuccessStatusAckResp statusAckResp = notifyParse(params);
        if (!statusAckResp.getStatus().equalsIgnoreCase("SUCCESS")) {
            log.error("充值单据验签名失败:{}", params);
            return "FAIL";
        }

        // 单据验证
        PayOrderDO byBizNo = payOrderRepository.getByOrderNoAndType(outTradeNo, payType);
        if (byBizNo == null || !byBizNo.getStatus().equals(OrderEnum.OrderStatus.PAYING.name())) {
            log.error("充值单据异常:{}", byBizNo);
            return "FAIL";
        }
        if (byBizNo.getStatus().equals(OrderEnum.OrderStatus.SUCCESS.name())) {
            return "SUCCESS";
        }
        Integer amount = byBizNo.getTotalAmount();
        if (totalAmount.intValue() != amount) {
            log.error("充值单据金额异常:{}", byBizNo);
            return "FAIL";
        }

        // 单据状态扭转
        doSuccessFinal(outTradeNo);

        return "SUCCESS";
    }


    private void doSuccessFinal(String bizNo) {
        // 更改账单状态
        payOrderRepository.updateStatusByOrderNoAndOldStatus(OrderEnum.OrderStatus.SUCCESS, bizNo, OrderEnum.OrderStatus.PAYING);

    }

    @Override
    public CreateOrderResp createSceneOrder(SceneOrderReq sceneOrderReq) {
        return buildPayOrder(sceneOrderReq, OrderEnum.PayType.SCENE_ORDER_TICK);
    }

    @Override
    public CreateOrderResp continueOrder(ContinueOrderReq continueOrderReq) {
        Integer orderId = continueOrderReq.getOrderId();

        PayOrderDO payOrderDO = payOrderRepository.getById(orderId);
        if (payOrderDO == null) {
            throw new BusinessException(BizErrorEnum.ORDER_NOT_EXIST);
        }
        if (payOrderDO.getValidTime().isBefore(LocalDateTime.now())) {
            throw new BusinessException(BizErrorEnum.RECHARGE_STATUS_ERROR, "下单时间已过期");
        }

        OrderEnum.PayType payType = OrderEnum.PayType.valueOf(payOrderDO.getType());

        AlipayClient alipayClient = buildAlipayClient();


        // 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        // SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody(payType.getDesc());
        model.setSubject(payType.getView());
        model.setOutTradeNo(payOrderDO.getBizNo());
        model.setTimeoutExpress("30m");
        model.setTotalAmount(MoneyUtil.convertFenToYuanDecimal(payOrderDO.getTotalAmount()));
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        if (payType.name().equals(OrderEnum.PayType.HOTEL_ORDER_ROOM.name())) {
            request.setNotifyUrl(hotelNotify);
        } else if (payType.name().equals(OrderEnum.PayType.SCENE_ORDER_TICK.name())) {
            request.setNotifyUrl(sceneNotify);
        }

        log.info("支付宝下单参数：{}", JSONObject.toJSONString(model));
        CreateOrderResp alipayOrderPayResp = new CreateOrderResp();
        try {
            // 这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            log.info("支付宝下单结果信息：{}", JSONObject.toJSONString(response));
            if (response.isSuccess()) {
                alipayOrderPayResp.setOrderInfo(response.getBody());
            } else {
                throw new BusinessException(CommonErrorEnum.SYSTEM_ERROR);
            }
        } catch (AlipayApiException e) {
            log.error("支付宝下单异常", e);
            throw new BusinessException(CommonErrorEnum.SYSTEM_ERROR);
        }

        return alipayOrderPayResp;
    }

    @Override
    public CreateOrderResp createHotelOrder(SceneOrderReq sceneOrderReq) {
        return buildPayOrder(sceneOrderReq, OrderEnum.PayType.HOTEL_ORDER_ROOM);
    }

    private CreateOrderResp buildPayOrder(SceneOrderReq sceneOrderReq, OrderEnum.PayType payType) {
        Integer axUid = sceneOrderReq.getAxUid();
        Integer num = 0;
        Integer amount = 0;
        LocalDate bookTime = sceneOrderReq.getBookTime();
        List<OrderInfo> orderReqOrderInfoList = sceneOrderReq.getOrderInfoList();
        List<Integer> orderListId = orderReqOrderInfoList.stream().map(OrderInfo::getOrderId).distinct().collect(Collectors.toList());
        String name = "";
        StringBuilder img = new StringBuilder();
        StringBuilder nameType = new StringBuilder();

        if (payType.name().equals(OrderEnum.PayType.SCENE_ORDER_TICK.name())) {
            Collection<SceneTicketDO> sceneTicketDOS = sceneTicketRepository.listByIds(orderListId);
            if (CollectionUtils.isEmpty(sceneTicketDOS)) {
                log.error("景点订单选择错误");
                throw new BusinessException(BizErrorEnum.PAY_NUM, "选择订单错误");
            }
            Map<Integer, SceneTicketDO> sceneTicketDOMap = sceneTicketDOS.stream().collect(Collectors.toMap(SceneTicketDO::getId, obj -> obj));
            for (OrderInfo orderInfo : orderReqOrderInfoList) {
                num += orderInfo.getNum();
                SceneTicketDO sceneTicketDO = sceneTicketDOMap.get(orderInfo.getOrderId());
                if (sceneTicketDO != null) {
                    amount += sceneTicketDO.getPrice() * orderInfo.getNum();
                    nameType.append(",").append(sceneTicketDO.getName()).append(" X ").append(orderInfo.getNum());
                }
            }
            SceneTicketDO sceneTicketDO = sceneTicketDOS.iterator().next();
            SceneDO sceneDO = sceneRepository.getById(sceneTicketDO.getSceneId());
            name = sceneDO.getName();
            img.append(",").append(sceneDO.getSmallImg());

        } else if (payType.name().equals(OrderEnum.PayType.HOTEL_ORDER_ROOM.name())) {
            Collection<HotelRoomDO> hotelRoomDOList = hotelRoomRepository.listByIds(orderListId);
            if (CollectionUtils.isEmpty(hotelRoomDOList)) {
                log.error("酒店订单选择错误");
                throw new BusinessException(BizErrorEnum.PAY_NUM, "选择订单错误");
            }
            Map<Integer, HotelRoomDO> hotelRoomDOMap = hotelRoomDOList.stream().collect(Collectors.toMap(HotelRoomDO::getId, obj -> obj));
            for (OrderInfo orderInfo : orderReqOrderInfoList) {
                num += orderInfo.getNum();
                HotelRoomDO hotelRoomDO = hotelRoomDOMap.get(orderInfo.getOrderId());
                if (hotelRoomDO != null) {
                    amount += hotelRoomDO.getPrice() * orderInfo.getNum();
                    nameType.append(",").append(hotelRoomDO.getRoomType()).append(" X ").append(orderInfo.getNum());
                    img.append(",").append(hotelRoomDO.getImg());
                }
            }
            HotelRoomDO hotelRoomDO = hotelRoomDOList.iterator().next();
            HotelDO hotelDO = hotelRepository.getById(hotelRoomDO.getHotelId());
            name = hotelDO.getName();
        }
        amount = amount * 100;

        log.info("req:{}, type：{},num：{}，amount：{}", sceneOrderReq, payType.name(), num, amount);
        if (num == 0) {
            throw new BusinessException(BizErrorEnum.PAY_NUM, "你还未选择数量");
        }
        String bizNo = BizNoUtil.getBizNo();
        AlipayClient alipayClient = buildAlipayClient();

        // 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        // SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody(payType.getDesc());
        model.setSubject(payType.getView());
        model.setOutTradeNo(bizNo);
        model.setTimeoutExpress("30m");
        model.setTotalAmount(MoneyUtil.convertFenToYuanDecimal(amount));
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        if (payType.name().equals(OrderEnum.PayType.HOTEL_ORDER_ROOM.name())) {
            request.setNotifyUrl(hotelNotify);
        } else if (payType.name().equals(OrderEnum.PayType.SCENE_ORDER_TICK.name())) {
            request.setNotifyUrl(sceneNotify);
        }

        log.info("支付宝下单参数：{}", JSONObject.toJSONString(model));
        CreateOrderResp alipayOrderPayResp = new CreateOrderResp();
        try {
            // 这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            log.info("支付宝下单结果信息：{}", JSONObject.toJSONString(response));
            if (response.isSuccess()) {
                alipayOrderPayResp.setOrderInfo(response.getBody());
            } else {
                throw new BusinessException(CommonErrorEnum.SYSTEM_ERROR);
            }
        } catch (AlipayApiException e) {
            log.error("支付宝下单异常", e);
            throw new BusinessException(CommonErrorEnum.SYSTEM_ERROR);
        }

        PayOrderDO payOrderDO = new PayOrderDO();
        payOrderDO.setPayChannel(PayChannelEnum.PayChannel.ALI_PAY.name());
        payOrderDO.setRealIdCard(sceneOrderReq.getIdCard());
        payOrderDO.setRealName(sceneOrderReq.getName());
        payOrderDO.setRealPhone(sceneOrderReq.getPhone());
        payOrderDO.setTotalAmount(amount);
        payOrderDO.setTotalNum(num);
        payOrderDO.setType(payType.name());
        payOrderDO.setAxUid(axUid);
        payOrderDO.setName(name);
        payOrderDO.setBookTime(bookTime);
        payOrderDO.setTypeName(nameType.toString().substring(1));
        payOrderDO.setBizNo(bizNo);
        payOrderDO.setImg(img.toString().substring(1));
        payOrderDO.setValidTime(LocalDateTime.now().plusMinutes(30));
        payOrderDO.setStatus(OrderEnum.OrderStatus.PAYING.name());
        payOrderRepository.save(payOrderDO);
        alipayOrderPayResp.setOrderId(payOrderDO.getOrderId());
        return alipayOrderPayResp;
    }


//    public void test() {
//        AlipayClient alipayClient = new DefaultAlipayClient(gateWay, appId, privateKey, "json", "UTF-8", publicKey, "RSA2");
//        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//        request.setBizContent("{" +
//                "\"timeout_express\":\"90m\"," +
//                "\"total_amount\":\"9.00\"," +
//                "\"product_code\":\"QUICK_MSECURITY_PAY\"," +
//                "\"body\":\"Iphone6 16G\"," +
//                "\"subject\":\"大乐透\"," +
//                "\"out_trade_no\":\"70501111111S001111119\"," +
//                "\"time_expire\":\"2016-12-31 10:05\"," +
//                "\"goods_type\":\"0\"," +
//                "\"promo_params\":\"{\\\"storeIdType\\\":\\\"1\\\"}\"," +
//                "\"passback_params\":\"merchantBizType%3d3C%26merchantBizNo%3d2016010101111\"," +
//                "\"extend_params\":{" +
//                "\"sys_service_provider_id\":\"2088511833207846\"," +
//                "\"hb_fq_num\":\"3\"," +
//                "\"hb_fq_seller_percent\":\"100\"," +
//                "\"industry_reflux_info\":\"{\\\\\\\"scene_code\\\\\\\":\\\\\\\"metro_tradeorder\\\\\\\",\\\\\\\"channel\\\\\\\":\\\\\\\"xxxx\\\\\\\",\\\\\\\"scene_data\\\\\\\":{\\\\\\\"asset_name\\\\\\\":\\\\\\\"ALIPAY\\\\\\\"}}\"," +
//                "\"card_type\":\"S0JP0000\"" +
//                "    }," +
//                "\"merchant_order_no\":\"20161008001\"," +
//                "\"enable_pay_channels\":\"pcredit,moneyFund,debitCardExpress\"," +
//                "\"store_id\":\"NJ_001\"," +
//                "\"specified_channel\":\"pcredit\"," +
//                "\"disable_pay_channels\":\"pcredit,moneyFund,debitCardExpress\"," +
//                "      \"goods_detail\":[{" +
//                "        \"goods_id\":\"apple-01\"," +
//                "\"alipay_goods_id\":\"20010001\"," +
//                "\"goods_name\":\"ipad\"," +
//                "\"quantity\":1," +
//                "\"price\":2000," +
//                "\"goods_category\":\"34543238\"," +
//                "\"categories_tree\":\"124868003|126232002|126252004\"," +
//                "\"body\":\"特价手机\"," +
//                "\"show_url\":\"http://www.alipay.com/xxx.jpg\"" +
//                "        }]," +
//                "\"ext_user_info\":{" +
//                "\"name\":\"李明\"," +
//                "\"mobile\":\"16587658765\"," +
//                "\"cert_type\":\"IDENTITY_CARD\"," +
//                "\"cert_no\":\"362334768769238881\"," +
//                "\"min_age\":\"18\"," +
//                "\"fix_buyer\":\"F\"," +
//                "\"need_check_info\":\"F\"" +
//                "    }," +
//                "\"business_params\":\"{\\\"data\\\":\\\"123\\\"}\"," +
//                "\"agreement_sign_params\":{" +
//                "\"personal_product_code\":\"CYCLE_PAY_AUTH_P\"," +
//                "\"sign_scene\":\"INDUSTRY|DIGITAL_MEDIA\"," +
//                "\"external_agreement_no\":\"test20190701\"," +
//                "\"external_logon_id\":\"13852852877\"," +
//                "\"access_params\":{" +
//                "\"channel\":\"ALIPAYAPP\"" +
//                "      }," +
//                "\"sub_merchant\":{" +
//                "\"sub_merchant_id\":\"2088123412341234\"," +
//                "\"sub_merchant_name\":\"滴滴出行\"," +
//                "\"sub_merchant_service_name\":\"滴滴出行免密支付\"," +
//                "\"sub_merchant_service_description\":\"免密付车费，单次最高500\"" +
//                "      }," +
//                "\"period_rule_params\":{" +
//                "\"period_type\":\"DAY\"," +
//                "\"period\":3," +
//                "\"execute_time\":\"2019-01-23\"," +
//                "\"single_amount\":10.99," +
//                "\"total_amount\":600," +
//                "\"total_payments\":12" +
//                "      }" +
//                "    }" +
//                "  }");
//        AlipayTradeAppPayResponse response = new AlipayTradeAppPayResponse();
//        try {
//            response = alipayClient.sdkExecute(request);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        if (response.isSuccess()) {
//            System.out.println("调用成功");
//        } else {
//            System.out.println("调用失败");
//        }
//    }
//
//    public void test1() {
//        AlipayClient alipayClient = buildAlipayClient();
//
//        // 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
//        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//        // SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
//        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
//        model.setBody("景点订票");
//        model.setSubject("订票");
//        model.setOutTradeNo(BizNoUtil.getBizNo());
//        model.setTimeoutExpress("30m");
//        model.setTotalAmount(MoneyUtil.convertFenToYuanDecimal(1));
//        model.setProductCode("QUICK_MSECURITY_PAY");
//        request.setBizModel(model);
//        request.setNotifyUrl(hotelNotify);
//
//        log.info("支付宝下单参数：{}", JSONObject.toJSONString(model));
//        CreateOrderResp alipayOrderPayResp = new CreateOrderResp();
//        try {
//            // 这里和普通的接口调用不同，使用的是sdkExecute
//            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
//            log.info("支付宝下单结果信息：{}", JSONObject.toJSONString(response));
//            if (response.isSuccess()) {
//                alipayOrderPayResp.setOrderInfo(response.getBody());
//            } else {
//                throw new BusinessException(CommonErrorEnum.SYSTEM_ERROR);
//            }
//        } catch (AlipayApiException e) {
//            log.error("支付宝下单异常", e);
//            throw new BusinessException(CommonErrorEnum.SYSTEM_ERROR);
//        }
//    }

    @Override
    public SuccessStatusAckResp closeOrder(String bizNo) {
        AlipayClient alipayClient = buildAlipayClient();
        AlipayTradeCloseRequest alipayTradeCloseRequest = new AlipayTradeCloseRequest();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("out_trade_no", bizNo);
        alipayTradeCloseRequest.setBizContent(jsonObject.toJSONString());

        SuccessStatusAckResp closeOrderResp = new SuccessStatusAckResp(OrderEnum.OrderStatus.FAIL.name());

        try {
            AlipayTradeCloseResponse response = alipayClient.execute(alipayTradeCloseRequest);
            if (response.isSuccess()) {
                closeOrderResp.setStatus(OrderEnum.OrderStatus.SUCCESS.name());
            } else {
                throw new BusinessException(CommonErrorEnum.SERVER_BUSY);
            }
        } catch (AlipayApiException e) {
            log.error("支付宝下单查询异常", e);
            throw new BusinessException(CommonErrorEnum.SERVER_BUSY);
        } catch (BusinessException e) {
            throw e;
        }
        return closeOrderResp;
    }

    @Override
    public void refundOrder(String bizNo, Integer amount) {
        AlipayClient alipayClient = buildAlipayClient();

        AlipayTradeRefundRequest alipayTradeRefundRequest = new AlipayTradeRefundRequest();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("out_trade_no", bizNo);
        jsonObject.put("refund_amount", MoneyUtil.convertFenToYuanDecimal(amount));
        alipayTradeRefundRequest.setBizContent(jsonObject.toJSONString());

        SuccessStatusAckResp successStatusAckResp = new SuccessStatusAckResp(OrderEnum.OrderStatus.FAIL.name());
        try {
            AlipayTradeRefundResponse alipayTradeRefundResponse = alipayClient.execute(alipayTradeRefundRequest);
            if (alipayTradeRefundResponse.isSuccess()) {
                successStatusAckResp.setStatus(OrderEnum.OrderStatus.SUCCESS.name());
            } else {
                throw new BusinessException(CommonErrorEnum.SERVER_BUSY);
            }
        } catch (AlipayApiException e) {
            log.error("支付宝退款异常", e);
            throw new BusinessException(CommonErrorEnum.SERVER_BUSY);
        } catch (BusinessException e) {
            throw e;
        }
    }

    @Override
    public SuccessStatusAckResp notifyParse(Map<String, String> notifyBody) {
        SuccessStatusAckResp successStatusAckResp = new SuccessStatusAckResp();
        successStatusAckResp.setStatus(OrderEnum.OrderStatus.FAIL.name());
//        try {
//            boolean flag = AlipaySignature.rsaCheckV1(notifyBody, aliPlublicKey, "UTF-8", "RSA2");
//            if (flag) {
//                successStatusAckResp.setStatus(OrderEnum.OrderStatus.SUCCESS.name());
//            }
//        } catch (Exception e) {
//            log.error("通知签名失败", e);
//        }
        // TODO: 2020/4/14 支付验签
        successStatusAckResp.setStatus(OrderEnum.OrderStatus.SUCCESS.name());
        return successStatusAckResp;
    }

    @Override
    public OrderStatusInfo queryOrder(String bizNo) {

        AlipayClient alipayClient = buildAlipayClient();
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("out_trade_no", bizNo);
        request.setBizContent(jsonObject.toJSONString());

        OrderEnum.OrderStatus aliPayOrderInfoResp = OrderEnum.OrderStatus.FAIL;
        AlipayTradeQueryResponse response = null;
        try {
            response = alipayClient.execute(request);
            if (response.isSuccess()) {
                aliPayOrderInfoResp = OrderEnum.OrderStatus.SUCCESS;
            } else {
                String subCode = response.getSubCode();
                if (subCode.equalsIgnoreCase("ACQ.TRADE_NOT_EXIST")) {
                    aliPayOrderInfoResp = OrderEnum.OrderStatus.NOT_EXISTS;
                }
            }
        } catch (AlipayApiException e) {
            log.error("支付宝下单查询异常", e);
        }
        log.info("支付宝下单查询信息：{}", response);

        OrderStatusInfo orderStatusInfo = new OrderStatusInfo();
        orderStatusInfo.setOrderStatus(aliPayOrderInfoResp);
        if (response != null) {
            orderStatusInfo.setTradeState(response.getTradeStatus());
        }

        return orderStatusInfo;
    }

    @Override
    public SuccessStatusAckResp sceneSuccessAck(SceneSuccessAckReq successAckReq) {
        String bizNo = successAckReq.getBizNo();

        SuccessStatusAckResp successStatusAckResp = new SuccessStatusAckResp();
        PayOrderDO payOrderDO = payOrderRepository.getByOrderNoAndType(bizNo, OrderEnum.PayType.SCENE_ORDER_TICK);
        if (payOrderDO == null) {
            throw new BusinessException(BizErrorEnum.ORDER_NOT_EXIST);
        }
        if (!payOrderDO.getStatus().equals(OrderEnum.OrderStatus.PAYING.name())) {
            successStatusAckResp.setStatus(payOrderDO.getStatus());
            return successStatusAckResp;
        }
        successStatusAckResp.setStatus(thirdAck(payOrderDO).name());
        return successStatusAckResp;
    }

    @Override
    public SuccessStatusAckResp hotelSuccessAck(SceneSuccessAckReq successAckReq) {
        String bizNo = successAckReq.getBizNo();

        SuccessStatusAckResp successStatusAckResp = new SuccessStatusAckResp();
        PayOrderDO payOrderDO = payOrderRepository.getByOrderNoAndType(bizNo, OrderEnum.PayType.HOTEL_ORDER_ROOM);
        if (payOrderDO == null) {
            throw new BusinessException(BizErrorEnum.ORDER_NOT_EXIST);
        }
        if (!payOrderDO.getStatus().equals(OrderEnum.OrderStatus.PAYING.name())) {
            successStatusAckResp.setStatus(payOrderDO.getStatus());
            return successStatusAckResp;
        }
        successStatusAckResp.setStatus(thirdAck(payOrderDO).name());
        return successStatusAckResp;
    }

    private OrderEnum.OrderStatus thirdAck(PayOrderDO payOrderDO) {

        String bizNo = payOrderDO.getBizNo();
        // 查询第三方状态
        OrderStatusInfo orderStatus = queryOrder(bizNo);
        switch (orderStatus.getOrderStatus()) {
            case SUCCESS:
                return successFinal(orderStatus.getTradeState(), payOrderDO.getBizNo());
            case FAIL:
            case NOT_EXISTS:
            default:
                boolean flag = payOrderRepository.updateStatusByOrderNoAndOldStatus(OrderEnum.OrderStatus.FAIL, bizNo, OrderEnum.OrderStatus.PAYING);
                if (!flag) {
                    throw new BusinessException(BizErrorEnum.RECHARGE_STATUS_ERROR);
                }
                return OrderEnum.OrderStatus.FAIL;
        }
    }

    private OrderEnum.OrderStatus successFinal(String tradeState, String bizNo) {


        //   * WAIT_BUYER_PAY（交易创建，等待买家付款）
        //	 * TRADE_CLOSED（未付款交易超时关闭，或支付完成后全额退款）
        //	 * TRADE_SUCCESS（交易支付成功）、
        //	 * TRADE_FINISHED（交易结束，不可退款）
        if (!(tradeState.equalsIgnoreCase("TRADE_SUCCESS") || tradeState.equalsIgnoreCase("TRADE_FINISHED"))) {
            return OrderEnum.OrderStatus.FAIL;
        }
        doSuccessFinal(bizNo);
        return OrderEnum.OrderStatus.SUCCESS;
    }

    @Override
    public BasePageResp<OrderListResp> orderList(OrderListReq orderListReq) {
        Integer axUid = orderListReq.getAxUid();
        Integer size = orderListReq.getSize();
        Integer index = orderListReq.getIndex();
        Integer type = orderListReq.getType();

        IPage<PayOrderDO> payOrderDOIPage = new Page<>(index, size);
        LambdaQueryWrapper<PayOrderDO> lambdaQueryWrapper = (new QueryWrapper<PayOrderDO>()).lambda();
        lambdaQueryWrapper.eq(PayOrderDO::getAxUid, axUid);
        if (type == 1) {
            lambdaQueryWrapper.eq(PayOrderDO::getType, OrderEnum.PayType.SCENE_ORDER_TICK.name());
        } else if (type == 2) {
            lambdaQueryWrapper.eq(PayOrderDO::getType, OrderEnum.PayType.HOTEL_ORDER_ROOM.name());
        } else {
            throw new BusinessException(CommonErrorEnum.PARAM_ERROR);
        }
        lambdaQueryWrapper.orderByDesc(PayOrderDO::getOrderId);

        payOrderDOIPage = payOrderRepository.page(payOrderDOIPage, lambdaQueryWrapper);
        List<OrderListResp> orderListRespList = BeanUtil.copyPropertiesByFastJson(payOrderDOIPage.getRecords(), OrderListResp.class);
        BasePageResp<OrderListResp> basePageResp = BeanUtil.copyPropertiesByFastJson(payOrderDOIPage, BasePageResp.class);
        basePageResp.setRecords(orderListRespList);

        orderListRespList.forEach(orderListResp -> {
            orderListResp.setTotalAmount(orderListResp.getTotalAmount() / 100);
            orderListResp.setStatus(OrderEnum.OrderStatus.valueOf(orderListResp.getStatus()).getView());
        });
        basePageResp.setLastPage(size * index >= payOrderDOIPage.getTotal());

        return basePageResp;
    }

    @Override
    public OrderDetailResp orderDetail(OrderDetailReq orderDetailReq) {
        Integer orderId = orderDetailReq.getOrderId();
        PayOrderDO payOrderDO = payOrderRepository.getById(orderId);
        if (payOrderDO == null) {
            throw new BusinessException(BizErrorEnum.ORDER_NOT_EXIST);
        }
        OrderDetailResp orderDetailResp = BeanUtil.copyPropertiesByFastJson(payOrderDO, OrderDetailResp.class);
        Long milliSecond = payOrderDO.getValidTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        orderDetailResp.setValidTime(milliSecond);
        orderDetailResp.setStatusName(OrderEnum.OrderStatus.valueOf(payOrderDO.getStatus()).getView());

        return orderDetailResp;
    }

    @Override
    public void payValidTime() {
        List<PayOrderDO> payOrderDOS = payOrderRepository.listByValidAndStatus();
        if (CollectionUtils.isEmpty(payOrderDOS)) {
            return;
        }
        List<Integer> validId = payOrderDOS.stream().map(PayOrderDO::getOrderId).collect(Collectors.toList());
        payOrderRepository.updateStatusByIdBatch(validId, OrderEnum.OrderStatus.TIME_OUT);
    }


    private AlipayClient buildAlipayClient() {
        return new DefaultAlipayClient(gateWay, appId, privateKey, "json", "UTF-8", publicKey, "RSA2");
    }
}
